home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / OWLSRC.PAK / PICTVAL.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  12.1 KB  |  563 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // Copyright (c) 1993, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   10.6  $
  6. //
  7. // Implementation of TPXPictureValidator, Paradox-picture input validator
  8. //----------------------------------------------------------------------------
  9. #pragma hdrignore SECTION
  10. #include <owl/pch.h>
  11. #if !defined(OWL_VALIDATE_H)
  12. # include <owl/validate.h>
  13. #endif
  14. #if !defined(OWL_APPLICAT_H)
  15. # include <owl/applicat.h>
  16. #endif
  17. #if !defined(OWL_APPDICT_H)
  18. # include <owl/appdict.h>
  19. #endif
  20. #if !defined(OWL_FRAMEWIN_H)
  21. # include <owl/framewin.h>
  22. #endif
  23. #include <ctype.h>
  24. #include <stdio.h>
  25.  
  26. OWL_DIAGINFO;
  27.  
  28. #if !defined(SECTION) || SECTION == 1
  29.  
  30. //
  31. //
  32. //
  33. TPXPictureValidator::TPXPictureValidator(const char far* pic, bool autoFill)
  34. :
  35.   TValidator(),
  36.   Pic(pic)
  37. {
  38.   Options = voOnAppend;
  39.   if (autoFill)
  40.     Options |= voFill;
  41.   if (Picture(0, false) != prEmpty)
  42.     TXValidator::Raise();
  43. }
  44.  
  45. //
  46. //
  47. //
  48. void
  49. TPXPictureValidator::Error(TWindow* owner)
  50. {
  51.   PRECONDITION(owner);
  52.   TApplication* app = owner->GetApplication();
  53.   string msgTmpl = app->LoadString(IDS_VALPXPCONFORM);
  54.   TAPointer<char> msg = new char[msgTmpl.length() + Pic.length() + 1];
  55.   sprintf(msg, msgTmpl.c_str(), (const char far*)Pic.c_str());
  56.   owner->MessageBox(msg, app->GetName(), MB_ICONEXCLAMATION|MB_OK);
  57. }
  58.  
  59. //
  60. //
  61. //
  62. bool
  63. TPXPictureValidator::IsValidInput(char far* input, bool suppressFill)
  64. {
  65.   bool autoFill = (Options&voFill) && !suppressFill;
  66.   return Pic.is_null() || Picture(input, autoFill) != prError;
  67. }
  68.  
  69. //
  70. //
  71. //
  72. bool
  73. TPXPictureValidator::IsValid(const char far* input)
  74. {
  75.   if (Pic.is_null())
  76.     return true;
  77.   TPicResult rslt = Picture(CONST_CAST(char far*,input), false);
  78.   return rslt == prComplete || rslt == prEmpty;
  79. }
  80.  
  81. //
  82. // Adjust the 'value' of the text, given a cursor position & an amount
  83. // Return the actual amount adjusted.
  84. //
  85. int
  86. TPXPictureValidator::Adjust(string& /*text*/, uint& /*begPos*/,
  87.                             uint& /*endPos*/, int /*amount*/)
  88. {
  89.   return 0;
  90. }
  91.  
  92. //
  93. //
  94. //
  95. inline bool
  96. TPXPictureValidator::IsComplete(TPicResult rslt)
  97. {
  98.   return rslt == prComplete || rslt == prAmbiguous;
  99. }
  100.  
  101. //
  102. //
  103. //
  104. inline bool
  105. TPXPictureValidator::IsIncomplete(TPicResult rslt)
  106. {
  107.   return rslt == prIncomplete || rslt == prIncompNoFill;
  108. }
  109.  
  110. //
  111. // Skip a character or a picture group
  112. //
  113. void
  114. TPXPictureValidator::ToGroupEnd(uint termCh, uint& i)
  115. {
  116.   int brkLevel = 0;
  117.   int brcLevel = 0;
  118.  
  119.   do {
  120.     if (i == termCh)
  121.       return;
  122.     switch (Pic[i]) {
  123.       case '[': brkLevel++; break;
  124.       case ']': brkLevel--; break;
  125.       case '{': brcLevel++; break;
  126.       case '}': brcLevel--; break;
  127.       case ';': i++; break;
  128.       case '*':
  129.         i++;
  130.         while (isdigit((uchar)Pic[i]))
  131.           i++;
  132.         ToGroupEnd(termCh, i);
  133.         continue;
  134.     }
  135.     i += CharSize((const char far*)Pic.c_str() + i);
  136.   } while (brkLevel || brcLevel);
  137. }
  138.  
  139. //
  140. // Find the next comma separator
  141. //
  142. bool
  143. TPXPictureValidator::SkipToComma(uint termCh, uint& i)
  144. {
  145.   for (;;) {
  146.     ToGroupEnd(termCh, i);
  147.     if (i == termCh)
  148.       return false;
  149.     if (Pic[i] == ',') {
  150.       i++;
  151.       return i < termCh;
  152.     }
  153.   }
  154. }
  155.  
  156. //
  157. // Calculate the end of a group (does not modify i)
  158. //
  159. uint
  160. TPXPictureValidator::CalcTerm(uint termCh, uint i)
  161. {
  162.   ToGroupEnd(termCh, i);
  163.   return i;
  164. }
  165.  
  166. //
  167. // The next group is repeated X times
  168. //
  169. TPicResult
  170. TPXPictureValidator::Iteration(char far* input, uint termCh, uint& i, uint& j)
  171. {
  172.   TPicResult rslt;
  173.   uint newTermCh;
  174.  
  175.   i++;  // Skip '*'
  176.  
  177.   // Retrieve number
  178.  
  179.   uint itr = 0;
  180.   for (; isdigit((uchar)Pic[i]); i++)
  181.     itr = itr * 10 + Pic[i] - '0';
  182.  
  183.   if (i >= termCh)
  184.     return prSyntax;
  185.  
  186.   newTermCh = CalcTerm(termCh, i);
  187.  
  188.   //
  189.   // if itr is 0 allow any number, otherwise enforce the number
  190.   //
  191.   uint k = i;
  192.   if (itr) {
  193.     for (uint m = 0; m < itr; m++) {
  194.       i = k;
  195.       rslt = Process(input, newTermCh, i, j);
  196.       if (!IsComplete(rslt)) {
  197.         if (rslt == prEmpty)  // Empty means incomplete since all are required
  198.           rslt = prIncomplete;
  199.         return rslt;
  200.       }
  201.     }
  202.   }
  203.   else {
  204.     do {
  205.       i = k;
  206.       rslt = Process(input, newTermCh, i, j);
  207.     } while (IsComplete(rslt));
  208.     if (rslt == prEmpty || rslt == prError) {
  209.       i++;
  210.       rslt = prAmbiguous;
  211.     }
  212.   }
  213.   i = newTermCh;
  214.   return rslt;
  215. }
  216.  
  217. //
  218. // Process a picture group
  219. //
  220. TPicResult
  221. TPXPictureValidator::Group(char far* input, uint termCh, uint& i, uint& j)
  222. {
  223.   uint groupTermCh = CalcTerm(termCh, i);
  224.   i++;
  225.   TPicResult rslt = Process(input, groupTermCh - 1, i, j);
  226.   if (!IsIncomplete(rslt))
  227.     i = groupTermCh;
  228.   return rslt;
  229. }
  230.  
  231. //
  232. //
  233. //
  234. TPicResult
  235. TPXPictureValidator::CheckComplete(uint termCh, uint& i, TPicResult rslt)
  236. {
  237.   uint j = i;
  238.   if (IsIncomplete(rslt)) {
  239.     // Skip optional pieces
  240.     for (;;) {
  241.       if (Pic[j] == '[')
  242.         ToGroupEnd(termCh, j);
  243.  
  244.       else if (Pic[j] == '*') {
  245.         if (!isdigit((uchar)Pic[j+1])) {
  246.           j++;
  247.           ToGroupEnd(termCh, j);
  248.         }
  249.         else
  250.           break;
  251.       }
  252.       else
  253.         break;
  254.  
  255.       if (j == termCh)
  256.         return prAmbiguous;  // end of the string, don't know if complete
  257.     }
  258.   }
  259.   return rslt;
  260. }
  261.  
  262. //
  263. //
  264. //
  265. #pragma warn -aus
  266. TPicResult
  267. TPXPictureValidator::Scan(char far* input, uint termCh, uint& i, uint& j)
  268. {
  269.   char ch;
  270.   TPicResult rslt = prEmpty;
  271.  
  272.   unsigned len = strlen(input);
  273.   while (i != termCh && Pic[i] != ',') {
  274.     if (j >= len)
  275.       return CheckComplete(termCh, i, rslt);
  276.  
  277.     ch = input[j];
  278.     switch (Pic[i]) {
  279.       case '#':
  280.         if (!isdigit((uchar)ch))
  281.           return prError;
  282.         else {
  283.           input[j++] = ch;
  284.           i++;
  285.         }
  286.         break;
  287.       case '?':
  288.         if (!isalpha((uchar)ch))
  289.           return prError;
  290.         else {
  291.           input[j++] = ch;
  292.           i++;
  293.         }
  294.         break;
  295.       case '&':
  296.         if (!isalpha((uchar)ch))
  297.           return prError;
  298.         else {
  299.           input[j++] = (char)toupper(ch);
  300.           i++;
  301.         }
  302.         break;
  303.       case '!': {
  304. #if defined(BI_DBCS_SUPPORT)
  305.         uint n = CharSize(&input[j]);
  306.         if (j + n >= len)
  307.           j = len;
  308.         else {
  309.           if (n == 1)
  310.             input[j++] = (char)toupper((uchar)ch);
  311.           else
  312.             j += n;
  313.         }
  314. #else
  315.         input[j++] = (char)toupper(ch);
  316. #endif
  317.         i++;
  318.         break;
  319.       }
  320.       case '@': {
  321. #if defined(BI_DBCS_SUPPORT)
  322.         uint n = CharSize(&input[j]);
  323.         if (j + n >= len)
  324.           j = len;
  325.         else
  326.           j += n;
  327. #else
  328.         input[j++] = ch;
  329. #endif
  330.         i++;
  331.         break;
  332.       }
  333.       case '*':
  334.         rslt = Iteration(input, termCh, i, j);
  335.         if (!IsComplete(rslt))
  336.           return rslt;
  337.         if (rslt == prError)
  338.           rslt = prAmbiguous;
  339.         break;
  340.       case '{':
  341.         rslt = Group(input, termCh, i, j);
  342.         if (!IsComplete(rslt))
  343.           return rslt;
  344.         break;
  345.       case '[':
  346.         rslt = Group(input, termCh, i, j);
  347.         if (IsIncomplete(rslt))
  348.           return rslt;
  349.         if (rslt == prError)
  350.           rslt = prAmbiguous;
  351.         break;
  352.       default: {
  353. #if defined(BI_DBCS_SUPPORT)
  354.         if (Pic[i] == ';')
  355.           i++;
  356.         uint n  = CharSize(&input[j]);
  357.         uint n2 = CharSize((const char far*)Pic.c_str() + i);
  358.  
  359.         if (j + n >= len)
  360.           n = len - j;
  361.         if (n == 1) {
  362.           if (ch == ' ') {
  363.             if (n != n2)
  364.               return prError;
  365.             input[j++] = Pic[i++];
  366.           }
  367.           else {
  368.             if (n != n2)
  369.               return prError;
  370.             if (toupper((uchar)Pic[i]) != toupper((uchar)ch))
  371.               return prError;
  372.             input[j++] = Pic[i++];
  373.           }
  374.         }
  375.         else {
  376.           if (n > n2)
  377.             return prError;
  378.           for (uint i1 = 0; i1 < n; i1++)
  379.             if (input[j+i1] != Pic[i+i1])
  380.               return prError;
  381.           while (n-- > 0)
  382.             input[j++] = Pic[i++];
  383.         }
  384. #else
  385.         if (Pic[i] == ';')
  386.           i++;
  387.         if (toupper(Pic[i]) != toupper(ch))
  388.           if (ch == ' ')
  389.             ch = Pic[i];
  390.           else
  391.             return prError;
  392.         input[j++] = Pic[i];
  393.         i++;
  394. #endif
  395.       }
  396.     }
  397.     if (rslt == prAmbiguous)
  398.       rslt = prIncompNoFill;
  399.     else
  400.       rslt = prIncomplete;
  401.   }
  402.  
  403.   return (rslt == prIncompNoFill) ? prAmbiguous : prComplete;
  404. }
  405. #pragma warn .aus
  406.  
  407. //
  408. //
  409. //
  410. TPicResult
  411. TPXPictureValidator::Process(char far* input, uint termCh, uint& i, uint& j)
  412. {
  413.   TPicResult rslt;
  414.   uint incompJ, incompI;
  415.   incompJ = incompI = 0;
  416.  
  417.   bool incomp = false;
  418.   uint oldI = i;
  419.   uint oldJ = j;
  420.   do {
  421.     rslt = Scan(input, termCh, i, j);
  422.  
  423.     //
  424.     // Only accept completes if they make it farther in the input
  425.     // stream from the last incomplete
  426.     //
  427.     if ((rslt==prComplete || rslt==prAmbiguous) && incomp && j < incompJ) {
  428.       rslt = prIncomplete;
  429.       j = incompJ;
  430.     }
  431.  
  432.     if (rslt == prError || rslt == prIncomplete) {
  433.       if (!incomp && rslt == prIncomplete) {
  434.         incomp = true;
  435.         incompI = i;
  436.         incompJ = j;
  437.       }
  438.       i = oldI;
  439.       j = oldJ;
  440.       if (!SkipToComma(termCh, i)) {
  441.         if (incomp) {
  442.           i = incompI;
  443.           j = incompJ;
  444.           return prIncomplete;
  445.         }
  446.         return rslt;
  447.       }
  448.       oldI = i;
  449.     }
  450.   } while (rslt == prError || rslt == prIncomplete);
  451.  
  452.   return (rslt == prComplete && incomp) ? prAmbiguous : rslt;
  453. }
  454.  
  455. //
  456. //
  457. //
  458. bool
  459. TPXPictureValidator::SyntaxCheck()
  460. {
  461.   if (Pic.is_null())
  462.     return false;
  463.   if (Pic[Pic.length()-1] == ';')
  464.     return false;
  465.   if (Pic[Pic.length()-1] == '*' && Pic[Pic.length()-2] != ';')
  466.     return false;
  467.  
  468.   int brkLevel = 0;
  469.   int brcLevel = 0;
  470.   for (uint i = 0; i < Pic.length(); ) {
  471.     switch (Pic[i]) {
  472.       case '[': brkLevel++; break;
  473.       case ']': brkLevel--; break;
  474.       case '{': brcLevel++; break;
  475.       case '}': brcLevel--; break;
  476.       case ';': i++;
  477.     }
  478.     i += CharSize((const char far*)Pic.c_str() + i);
  479.   }
  480.   return !(brkLevel || brcLevel);
  481. }
  482.  
  483. //
  484. //
  485. //
  486. TPicResult
  487. TPXPictureValidator::Picture(char far* input, bool autoFill)
  488. {
  489.   if (!SyntaxCheck())
  490.     return prSyntax;
  491.   if (!input || !*input)
  492.     return prEmpty;
  493.  
  494.   uint j = 0;  // index for input[]
  495.   uint i = 0;  // index for Pic[]
  496.  
  497.   TPicResult rslt = Process(input, Pic.length(), i, j);
  498.   if (rslt != prError && rslt != prSyntax && j < strlen(input))
  499.     rslt = prError;
  500.  
  501.   // If the result is incomplete & autofill is requested, then copy literal
  502.   // characters from the picture over to the input.
  503.   //
  504.   if (rslt == prIncomplete && autoFill) {
  505.     bool  reprocess = false;
  506.     while (i < Pic.length() && !strchr("#?&!@*{}[],", Pic[i])) {
  507.       if (Pic[i] == ';')
  508.         i++;
  509. #if defined(BI_DBCS_SUPPORT)
  510.       uint k = strlen(input);
  511.       uint n = CharSize((const char far*)Pic.c_str() + i);
  512.       memmove(input + k, Pic.c_str() + i, n);
  513.       input[k + n] = '\0';
  514.       i += n;
  515.       j += n;
  516. #else
  517.       input[j++] = Pic[i++];
  518. #endif
  519.       reprocess = true;
  520.     }
  521.     if (reprocess) {
  522.       input[j] = 0;   // terminate the copy, since we are probably appending
  523.       j = i = 0;
  524.       rslt = Process(input, Pic.length(), i, j);
  525.     }
  526.   }
  527.  
  528.   return (rslt == prAmbiguous) ? prComplete
  529.                                : (rslt == prIncompNoFill) ? prIncomplete : rslt;
  530. }
  531.  
  532. #endif
  533. #if !defined(SECTION) || SECTION == 2
  534.  
  535. IMPLEMENT_STREAMABLE1(TPXPictureValidator, TValidator);
  536.  
  537. #if !defined(BI_NO_OBJ_STREAMING)
  538.  
  539. //
  540. //
  541. //
  542. void*
  543. TPXPictureValidator::Streamer::Read(ipstream& is, uint32 /*version*/) const
  544. {
  545.   ReadBaseObject((TValidator*)GetObject(), is);
  546.   is >> GetObject()->Pic;
  547.   return GetObject();
  548. }
  549.  
  550. //
  551. //
  552. //
  553. void
  554. TPXPictureValidator::Streamer::Write(opstream& os) const
  555. {
  556.   WriteBaseObject((TValidator*)GetObject(), os);
  557.   os << GetObject()->Pic;
  558. }
  559.  
  560. #endif  // if !defined(BI_NO_OBJ_STREAMING)
  561.  
  562. #endif
  563.